<template>
  <!-- component 动态组件不能在 , 组件内部使用 ;嵌套使用-->
  <div class="scroll" ref="scrollContainer">
    <div class="scroll-content" ref="scrollContent">
      <!-- 第一段内容 -->
      <div
        class="scroll-group scroll-first items-center"
        ref="groupA"
        :style="{ transform: groupATransform }"
      >
        <slot name="cell" :list="groupAList" prefix="first"></slot>
      </div>
      <!-- 第二段内容 -->
      <div
        v-if="groupA && groupBList.length"
        class="scroll-group scroll-second items-center"
        ref="groupB"
        :style="{ transform: groupBTransform }"
      >
        <slot name="cell" :list="groupBList" prefix="second"></slot>
      </div>
    </div>
  </div>
</template>

<script setup name="infoScroll">
import { ref, onMounted, onBeforeUnmount, nextTick, computed } from "vue";

const props = defineProps({
  // 数据源数组: 数据长度不能小于 8
  list: {
    type: Array,
    default: [],
  },
  // 默认循环
  loop: {
    type: Boolean,
    default: true,
  },
  // 初始滚动速度，单位：px/s
  speed: {
    type: Number,
    default: 100,
  },
});

// 模拟的中奖信息数据
let items = [];

// 默认一组至少有 4 个数据
let part = 4;

/**
 * @description: findSmallestDivisor(Math.floor(Math.random() * 9999));随机数为 ${randomNumber}，能整除它的最小数（不小于 3）为 ${smallestDivisor}
 * @param {*} num
 */
function findSmallestDivisor(num) {
  if (num < 2) {
    return null;
  }
  for (let i = Math.max(3, num > 3 ? 2 : 0); i <= num; i++) {
    if (num % i === 0) {
      return i;
    }
  }
  return num;
}

/**
 * @description: 数据源初始化
 * 1. 防止出现数据太少的情况
 * 2. 加载组件
 */
async function initDataSource() {
  // 1. 防止出现数据太少的情况
  if (props.list.length > 1) {
    if (props.list.length < 8) {
      items = props.list
        .concat(props.list)
        .concat(props.list)
        .concat(props.list)
        .concat(props.list)
        .concat(props.list)
        .concat(props.list)
        .concat(props.list);
    } else {
      const partTemp = findSmallestDivisor(props.list.length);
      if (partTemp == props.list.length) {
        items = props.list
          .concat(props.list)
          .concat(props.list)
          .concat(props.list);
      } else {
        items = JSON.parse(JSON.stringify(props.list));
      }
    }
  } else {
    return console.error("infoScroll组件 list 属性:长度必须大于 1");
  }
  // 1.1 求出一组展示几个
  part = findSmallestDivisor(items.length);
  // console.log("part:", part);
}

await initDataSource();

// 将数据分为每组 5 个，共 20 组
const groups = Array.from({ length: items.length / part }, (_, i) =>
  items.slice(i * part, (i + 1) * part)
);

// console.log("groups:", groups);

// 引用
const scrollContainer = ref(null);
const groupA = ref(null);
const groupB = ref(null);

// 列表数据
const groupAList = ref(groups[0]);
const groupBList = ref(groups[1]);

// 宽度变量
const groupAWidth = ref(0);
const groupBWidth = ref(0);

// 当前渲染的组索引
let currentPart = 2; // groupA 是 0, groupB 是 1, 下一个是 2

// A 和 B 的 left 位置（使用 transform）
const groupAleft = ref(0);
const groupBleft = ref(0);

// 动画帧 ID
let animationFrameId = null;

// 上一帧的时间戳
let lastTimestamp = null;

const groupATransform = computed(
  () => `translateX(${groupAleft.value || 0}px)`
);
const groupBTransform = computed(
  () => `translateX(${groupBleft.value || 0}px)`
);

// 开始滚动函数
const startScrolling = (timestamp) => {
  if (!lastTimestamp) {
    lastTimestamp = timestamp;
  }
  const delta = timestamp - lastTimestamp;
  lastTimestamp = timestamp;

  const deltaSeconds = delta / 1000;
  const distance = (props.speed * deltaSeconds).toFixed(5);

  // 更新位置
  groupAleft.value -= distance;
  groupBleft.value -= distance;

  // 调试日志
  // console.log(`Delta: ${delta}ms, Distance: ${distance}px`);
  // console.log(`GroupA left: ${groupAleft.value}px, GroupB left: ${groupBleft.value}px`);

  // 检查 A 是否完全滚出视图
  if (groupAleft.value + groupAWidth.value < 0) {
    // 重置 A 到 B 后面
    groupAleft.value = groupBleft.value + groupBWidth.value;
    // console.log("重置 A 的位置:", groupAleft.value);

    // 赋值下一个组
    groupAList.value = groups[currentPart % groups.length];
    // console.log(
    //   "Assigning GroupAList to group index:",
    //   currentPart % groups.length
    // );
    currentPart += 1;

    // 更新 groupAWidth
    setTimeout(() => {
      if (groupA.value) {
        groupAWidth.value = groupA.value.scrollWidth;
        // console.log("更新 A 宽度:", groupAWidth.value);
      }
    }, 1);
  }

  // 检查 B 是否完全滚出视图
  if (groupBleft.value + groupBWidth.value < 0) {
    // 重置 B 到 A 后面
    groupBleft.value = groupAleft.value + groupAWidth.value;
    // console.log("重置 B 的位置:", groupBleft.value);

    // 赋值下一个组
    groupBList.value = groups[currentPart % groups.length];
    // console.log(
    //   "Assigning GroupBList to group index:",
    //   currentPart % groups.length
    // );
    currentPart += 1;

    // 更新 groupBWidth
    setTimeout(() => {
      if (groupB.value) {
        groupBWidth.value = groupB.value.scrollWidth;
        // console.log("更新 A 宽度:", groupBWidth.value);
      }
    }, 1);
  }

  // 递归调用下一帧
  animationFrameId = requestAnimationFrame(startScrolling);
};

// 组件挂载后
onMounted(async () => {
  await nextTick(); // 确保 DOM 已渲染

  setTimeout(() => {
    if (groupA.value) {
      groupAWidth.value = groupA.value.scrollWidth;
      // console.log("初始化 A Width:", groupAWidth.value);
      // 设置第一次 B 的位置
      groupBleft.value = groupAWidth.value;
      // console.log("初始化 B Left Position:", groupBleft.value);
    }

    if (groupB.value) {
      groupBWidth.value = groupB.value.scrollWidth;
      // console.log("初始化 B Width:", groupBWidth.value);
      // 开始动画循环
      animationFrameId = requestAnimationFrame(startScrolling);
    }
  }, 10);
});

// 组件卸载前
onBeforeUnmount(() => {
  animationFrameId && cancelAnimationFrame(animationFrameId);
});
</script>

<style scoped lang="scss">
.scroll {
  width: 100vw;
  overflow: hidden; /* 隐藏溢出，实现自定义滚动 */
  position: relative;

  &-content {
    display: flex;
    min-height: 25 * 2px;
    position: relative;
  }

  &-group {
    display: flex;
    align-items: center;
    will-change: transform; /* 提示浏览器优化 transform */
    position: absolute;
    top: 0; /* 确保组在同一行 */
  }
}

.scroll-item {
  min-height: 25 * 2px;
  padding-right: 15 * 2px;
  white-space: nowrap;
  display: flex;
  align-items: center;

  &-index {
    font-size: 20px;
    font-weight: 900;
    color: red;
    margin-left: 5px;
  }
}
</style>
